﻿using System;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.ServiceModel.DomainServices.Client;
using IssueVision.Data.Web;
using IssueVision.Common;

namespace IssueVision.Model
{
    [Export(typeof(IIssueVisionModel))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class IssueVisionModel : IIssueVisionModel
    {
        #region "Private Data"
        private IssueVisionContext _ctx;
        #endregion "Private Data"

        #region "Protected Propertes"
        protected IssueVisionContext Context
        {
            get
            {
                if (_ctx == null)
                {
                    _ctx = IssueVisionContext.Instance;
                    _ctx.PropertyChanged += _ctx_PropertyChanged;
                }

                return _ctx;
            }
        }
        #endregion "Protected Propertes"

        #region "IIssueVisionModel Interface implementation"

        public void GetIssueTypesAsync()
        {
            PerformQuery(Context.GetIssueTypesQuery(), GetIssueTypesComplete);
        }

        public void GetPlatformsAsync()
        {
            PerformQuery(Context.GetPlatformsQuery(), GetPlatformsComplete);
        }

        public void GetResolutionsAsync()
        {
            PerformQuery(Context.GetResolutionsQuery(), GetResolutionsComplete);
        }

        public void GetStatusesAsync()
        {
            PerformQuery(Context.GetStatusesQuery(), GetStatusesComplete);
        }

        public void GetSubStatusesAsync()
        {
            PerformQuery(Context.GetSubStatusesQuery(), GetSubStatusesComplete);
        }

        public void GetUsersAsync()
        {
            PerformQuery(Context.GetUsersQuery(), GetUsersComplete);
        }

        public void GetCurrentUserAsync()
        {
            PerformQuery(Context.GetCurrentUserQuery(), GetCurrentUserComplete);
        }

        public void GetSecurityQuestionsAsync()
        {
            PerformQuery(Context.GetSecurityQuestionsQuery(), GetSecurityQuestionsComplete);
        }

        public void GetMyIssuesAsync()
        {
            PerformQuery(Context.GetMyIssuesQuery(), GetMyIssuesComplete);
        }

        public void GetAllIssuesAsync()
        {
            PerformQuery(Context.GetIssuesQuery(), GetAllIssuesComplete);
        }

        public void GetAllUnresolvedIssuesAsync()
        {
            PerformQuery(Context.GetAllUnResolvedIssuesQuery(), GetAllUnresolvedIssuesComplete);
        }

        public void GetActiveBugCountByMonthAsync(int numberOfMonth)
        {
            Context.GetActiveBugCountByMonth(numberOfMonth, s =>
            {
                if (GetActiveBugCountByMonthComplete != null)
                {
                    try
                    {
                        Exception ex = null;
                        if (s.HasError)
                        {
                            ex = s.Error;
                            s.MarkErrorAsHandled();
                        }
                        GetActiveBugCountByMonthComplete(this, new InvokeOperationEventArgs(s, ex));
                    }
                    catch (Exception ex)
                    {
                        GetActiveBugCountByMonthComplete(this, new InvokeOperationEventArgs(ex));
                    }
                }
            }, null);
        }

        public void GetResolvedBugCountByMonthAsync(int numberOfMonth)
        {
            Context.GetResolvedBugCountByMonth(numberOfMonth, s =>
            {
                if (GetResolvedBugCountByMonthComplete != null)
                {
                    try
                    {
                        Exception ex = null;
                        if (s.HasError)
                        {
                            ex = s.Error;
                            s.MarkErrorAsHandled();
                        }
                        GetResolvedBugCountByMonthComplete(this, new InvokeOperationEventArgs(s, ex));
                    }
                    catch (Exception ex)
                    {
                        GetResolvedBugCountByMonthComplete(this, new InvokeOperationEventArgs(ex));
                    }
                }
            }, null);
        }

        public void GetActiveBugCountByPriorityAsync()
        {
            Context.GetActiveBugCountByPriority(s =>
            {
                if (GetActiveBugCountByPriorityComplete != null)
                {
                    try
                    {
                        Exception ex = null;
                        if (s.HasError)
                        {
                            ex = s.Error;
                            s.MarkErrorAsHandled();
                        }
                        GetActiveBugCountByPriorityComplete(this, new InvokeOperationEventArgs(s, ex));
                    }
                    catch (Exception ex)
                    {
                        GetActiveBugCountByPriorityComplete(this, new InvokeOperationEventArgs(ex));
                    }
                }
            }, null);
        }

        public Issue AddNewIssue()
        {
            var g = new Issue
            {
                IssueID = 0,
                OpenedDate = DateTime.Now,
                OpenedByID = WebContext.Current.User.Identity.Name,
                LastChange = DateTime.Now,
                ChangedByID = WebContext.Current.User.Identity.Name,
                AssignedToID = null,
                Priority = 2,
                Severity = 2,
                StatusID = 0,
                SubStatusID = null
            };
            Context.Issues.Add(g);
            return g;
        }

        public void RemoveAttribute(Data.Web.Attribute attribute)
        {
            if (Context.Attributes.Contains(attribute))
                Context.Attributes.Remove(attribute);
        }

        public void RemoveFile(File file)
        {
            if (Context.Files.Contains(file))
                Context.Files.Remove(file);
        }

        public void SaveChangesAsync()
        {
            Context.SubmitChanges(s =>
            {
                if (SaveChangesComplete != null)
                {
                    try
                    {
                        Exception ex = null;
                        if (s.HasError)
                        {
                            ex = s.Error;
                            s.MarkErrorAsHandled();
                        }
                        SaveChangesComplete(this, new SubmitOperationEventArgs(s, ex));
                    }
                    catch (Exception ex)
                    {
                        SaveChangesComplete(this, new SubmitOperationEventArgs(ex));
                    }
                }
            }, null);
        }

        /// <summary>
        /// Reject any pending changes
        /// </summary>
        public void RejectChanges()
        {
            Context.RejectChanges();
        }

        /// <summary>
        /// True if _ctx.HasChanges is true; otherwise, false
        /// </summary>
        public Boolean HasChanges
        {
            get
            {
                return _hasChanges;
            }

            private set
            {
                if (_hasChanges != value)
                {
                    _hasChanges = value;
                    OnPropertyChanged("HasChanges");
                }
            }
        }
        private Boolean _hasChanges;

        /// <summary>
        /// True if either "IsLoading" or "IsSubmitting" is
        /// in progress; otherwise, false
        /// </summary>
        public Boolean IsBusy
        {
            get
            {
                return _isBusy;
            }

            private set
            {
                if (_isBusy != value)
                {
                    _isBusy = value;
                    OnPropertyChanged("IsBusy");
                }
            }
        }
        private Boolean _isBusy;

        public event EventHandler<SubmitOperationEventArgs> SaveChangesComplete;
        public event EventHandler<EntityResultsArgs<IssueType>> GetIssueTypesComplete;
        public event EventHandler<EntityResultsArgs<Platform>> GetPlatformsComplete;
        public event EventHandler<EntityResultsArgs<Resolution>> GetResolutionsComplete;
        public event EventHandler<EntityResultsArgs<Status>> GetStatusesComplete;
        public event EventHandler<EntityResultsArgs<SubStatus>> GetSubStatusesComplete;
        public event EventHandler<EntityResultsArgs<User>> GetUsersComplete;
        public event EventHandler<EntityResultsArgs<User>> GetCurrentUserComplete;
        public event EventHandler<EntityResultsArgs<SecurityQuestion>> GetSecurityQuestionsComplete;
        public event EventHandler<EntityResultsArgs<Issue>> GetMyIssuesComplete;
        public event EventHandler<EntityResultsArgs<Issue>> GetAllIssuesComplete;
        public event EventHandler<EntityResultsArgs<Issue>> GetAllUnresolvedIssuesComplete;
        public event EventHandler<InvokeOperationEventArgs> GetActiveBugCountByMonthComplete;
        public event EventHandler<InvokeOperationEventArgs> GetResolvedBugCountByMonthComplete;
        public event EventHandler<InvokeOperationEventArgs> GetActiveBugCountByPriorityComplete;

        #endregion "IIssueVisionModel Interface implementation"

        #region "INotifyPropertyChanged Interface implementation"
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion "INotifyPropertyChanged Interface implementation"

        #region "ICleanup Interface implementation"
        public void Cleanup()
        {
            if (_ctx != null)
            {
                // unregister event handler
                _ctx.PropertyChanged -= _ctx_PropertyChanged;
                _ctx = null;
            }
        }
        #endregion "ICleanup Interface implementation"

        #region "Private Methods"
        private void _ctx_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "HasChanges":
                    HasChanges = _ctx.HasChanges;
                    break;
                case "IsLoading":
                    IsBusy = _ctx.IsLoading;
                    break;
                case "IsSubmitting":
                    IsBusy = _ctx.IsSubmitting;
                    break;
            }
        }

        private void PerformQuery<T>(EntityQuery<T> qry, EventHandler<EntityResultsArgs<T>> evt) where T : Entity
        {
            Context.Load(qry, LoadBehavior.RefreshCurrent, r =>
            {
                if (evt != null)
                {
                    try
                    {
                        if (r.HasError)
                        {
                            evt(this, new EntityResultsArgs<T>(r.Error));
                            r.MarkErrorAsHandled();
                        }
                        else
                        {
                            evt(this, new EntityResultsArgs<T>(r.Entities));
                        }
                    }
                    catch (Exception ex)
                    {
                        evt(this, new EntityResultsArgs<T>(ex));
                    }
                }
            }, null);
        }
        #endregion "Private Methods"                                     
    }
}